#include"head.h"
#include"common.h"
#include"rule.h"
#include"nat.h"
#include"conn.h"
#include"hook.h"
static struct sock *nlsk = NULL;
extern unsigned int DEFAULT_ACTION ;

int nlSend(unsigned int pid, void *data, unsigned int len) {
	int retval;
	struct nlmsghdr *nlh;
	struct sk_buff *skb;
	// init sk_buff
	skb = nlmsg_new(len, GFP_ATOMIC);
	if (skb == NULL) {
		printk(KERN_WARNING "[firewall] alloc reply nlmsg skb failed!\n");
		return -1;
	}
	nlh = nlmsg_put(skb, 0, 0, 0, NLMSG_SPACE(len) - NLMSG_HDRLEN, 0);
	// send data
	memcpy(NLMSG_DATA(nlh), data, len);
    //NETLINK_CB(skb).portid = 0;
	NETLINK_CB(skb).dst_group = 0;
	retval = netlink_unicast(nlsk, skb, pid, MSG_DONTWAIT);
	printk("[firewall] send to user pid=%d,len=%d,ret=%d\n", pid, nlh->nlmsg_len - NLMSG_SPACE(0), retval);
	return retval;
}
int kernel2cmd(unsigned int pid, const char *msg) {
    struct KernelResponse *rsp;  // 创建结构体实例
	unsigned int memLen;
	void* mem;
	memLen = sizeof(struct KernelResponse) + strlen(msg) + 1;
	mem=kzalloc(memLen, GFP_ATOMIC);
	   if(mem == NULL) {
        printk(KERN_WARNING "[fw k2app] kzalloc fail.\n");
        return 0;
    }

   	rsp = (struct KernelResponse *)mem;
    rsp->arrlen=0;
	rsp->rsplen =  strlen(msg);
    rsp->data =(char *)rsp+sizeof(struct KernelResponse);
    memcpy(mem+sizeof(struct KernelResponse), msg, strlen(msg));  // 假设 KernelResponse 结构体中有 body 字段
 printk("%d",rsp->rsplen);
    // 发送消息
    nlSend(pid, rsp, memLen);  // 直接发送结构体的地址
	kfree(mem);
    return memLen;
}

 int dealcmdMessage(unsigned int pid, void *msg, unsigned int len) {
     struct cmdRequest *req;
     struct KernelResponseHeader *rspH;
     void* mem;
    unsigned int rspLen = 0;
    req = (struct cmdRequest *) msg;
    
 switch (req->tp)
 { 
	case REQ_GETAllIPRules:
         mem = formAllIPRules(&rspLen);
        
        if(mem == NULL) {
            printk(KERN_WARNING "dealcmdMessage() formAllIPRules fail.\n");
            kernel2cmd(pid, "form all rules fail.");
            break;
        }
       nlSend(pid, mem, rspLen);
        kfree(mem);
        break;
        
    case REQ_ADDIPRule:
    printk(" %s\n",req->msg.ipRule.name);
     addIPRuleToChain(req->msg.ipRule);
    kernel2cmd(pid, "success add rule\n") ;

        break;
    case REQ_DELIPRule:
   
        if(delIPRuleFromChain(req->ruleName)==0)
        {
            printk("no such rules\n");
             kernel2cmd(pid, "no such rule\n") ;
        }
        printk("[fw k2app] success del %s rules.\n",req->ruleName);
        kernel2cmd(pid, "success del\n") ;
        kfree(rspH);
        break;

    case REQ_GETAllConns:
        mem = formAllConns(&rspLen);
        if(mem == NULL) {
            printk(KERN_WARNING "[fw k2app] formAllConns fail.\n");
            kernel2cmd(pid, "form all conns fail.");
            break;
        }
        nlSend(pid, mem, rspLen);
        kfree(mem);
        break;
   
    case REQ_GETNATRules:
        mem = formAllNATRules(&rspLen);
        if(mem == NULL) {
            printk(KERN_WARNING "[fw k2app] formAllNATRules fail.\n");
              kernel2cmd(pid, "form all NAT rules fail.");
            break;
        }
        nlSend(pid, mem, rspLen);
        kfree(mem);
        break;
    case REQ_ADDNATRule:
        if(addNATRuleToChain(req->msg.natRule)==NULL) {
            rspLen = kernel2cmd(pid, "Fail: please retry it.");
            printk("[fw k2app] add NAT rule fail.\n");
        } else {
            kernel2cmd(pid, "Success add nat\n");
            printk("[fw k2app] add one NAT rule success.\n");
        }
        break;

     case REQ_SETdefault:
        if(req->msg.defaultAction == 1) {
            DEFAULT_ACTION = NF_ACCEPT;
            kernel2cmd(pid, "Set default action to ACCEPT.\n");
   
        } else {
            DEFAULT_ACTION = NF_DROP;
            kernel2cmd(pid, "Set default action to DROP.\n");
           
        }
  
        break;
    default:
    kernel2cmd(pid, "No such req.");
       break;
 }

    return 1;
 }


void nlRecv(struct sk_buff *skb) {
	void *data;
	struct nlmsghdr *nlh = NULL;
	unsigned int pid,len;
	 
    // check skb
    nlh = nlmsg_hdr(skb);
	
    // deal data
	data = NLMSG_DATA(nlh);
    pid = nlh->nlmsg_pid;
    len = nlh->nlmsg_len - NLMSG_SPACE(0);//datalen

	printk("[firewall] data receive from user: user_pid=%d, len=%d\n", pid, len);
    
	// kernel2cmd(pid,"test1 success\n");
	dealcmdMessage(pid, data, len);
	

}

struct netlink_kernel_cfg nltest_cfg = {
	.groups = 0,
	.flags = 0,
	.input = nlRecv,
	.cb_mutex = NULL,
	.bind = NULL,
	.unbind = NULL,
	.compare = NULL,
};

struct sock *netlink_init(void) {
    nlsk = netlink_kernel_create(&init_net, 17, &nltest_cfg);
	if (!nlsk) {
		printk(KERN_WARNING " create a netlink socket failed\n");
		return NULL;
	}
	printk("netlink_kernel_create() success, nlsk = %p\n", nlsk);
    return nlsk;
}

void netlink_release(void) {
    netlink_kernel_release(nlsk);
}



